home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / cprog.EXE / C-DERSI6.C < prev    next >
C/C++ Source or Header  |  1996-06-25  |  12KB  |  332 lines

  1.  
  2.                                  Lesson 5.
  3.  
  4.                       The Pre-processor and Header Files.
  5.  
  6. The pre-processor is activated by a '#' character in column one of the source
  7. code. There are several statements vis:
  8.  
  9. #include
  10.  
  11. #define
  12. #undef
  13.  
  14. #if
  15. #else
  16. #endif
  17.  
  18. #ifdef
  19. #ifndef
  20.  
  21. #pragma
  22.  
  23.   #include.
  24.  
  25.   In the programming examples presented in the previous lessons you will
  26. probably have noticed that there is this statement:
  27.  
  28. #include <stdio.h>
  29.  
  30. right at the start of the program text. This statement tells the pre-processor
  31. to include the named file in the your program text. As far as the compiler is
  32. concerned this text appears just as if you had typed it yourself!
  33.  
  34.   This is one of the more useful facilities provided by the 'C' language.
  35. The #include statement is frequently combined with the #if construct.
  36. In this program fragment the file "true.h" is included in your program
  37. if the pre-processor symbol FLAG is true, and "false.h" included if FLAG
  38. is false.
  39.  
  40. #if ( FLAG )
  41. # include "true.h"
  42. #else
  43. # include "false.h"
  44. #endif
  45.  
  46. This mechanism has many uses, one of which is to provide
  47. portability between all the 57,000 slightly different versions of unix and also
  48. other operating systems. Another use is to be able to alter the way in which
  49. your program behaves according to the preference of the user.
  50.  
  51. Of course, you will be asking the question "Where is the file stored?".
  52. Well, if the filename is delimited by the "<" and ">" characters as in the
  53. example above the file comes from the /usr/include directory, but if the name
  54. of the file is delimited by quotes then the file is to be found in your current
  55. working directory. (This is not quite the whole truth as 'C' compilers allow
  56. you to extend the search path for the include files using command line option
  57. switches. - See your compiler manual for the whole story. )
  58.  
  59. So, I would like to suggest that you to have a look around the /usr/include
  60. directory and its /sys sub-directory. You should use either your editor
  61. in 'view' mode or the pg utility. This will ensure that you can't have an
  62. accident and alter one of the files by mistake if you are slightly silly
  63. and just happen to be logged on as the super-user.
  64.  
  65. A typical file to examine is usr/include/time.h.
  66.  
  67. It's quite small so here it is.
  68.  
  69. /*  Copyright (c) 1984 AT&T  */
  70. /*    All Rights Reserved    */
  71.  
  72. /*  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T  */
  73. /*  The copyright notice above does not evidence any     */
  74. /*  actual or intended publication of such source code.  */
  75.  
  76. #ident  "@(#)/usr/include/time.h.sl 1.5 4.2 04/20/87 18195 AT&T-SF"
  77. /*  3.0 SID #  1.2  */
  78. struct  tm {  /* see ctime(3) */
  79.   int  tm_sec;
  80.   int  tm_min;
  81.   int  tm_hour;
  82.   int  tm_mday;
  83.   int  tm_mon;
  84.   int  tm_year;
  85.   int  tm_wday;
  86.   int  tm_yday;
  87.   int  tm_isdst;
  88. };
  89. extern struct tm *gmtime(), *localtime();
  90. extern char *ctime(), *asctime();
  91. int  cftime(),  ascftime();
  92. extern void tzset();
  93. extern long timezone, altzone;
  94. extern int daylight;
  95. extern char *tzname[];
  96.  
  97.   As you can see ( forgetting about the comments and #ident ) there are three
  98. different uses for the file.
  99.  
  100.   a) The definition of data structures and types.
  101.   b) The declaration of functions which use the data structures.
  102.   c) The declaration of of external data objects.
  103.  
  104.   These lines of code are all you need in your program in order to be able to
  105. use, in this case, the library routine to access the clock in the computer,
  106. but of course the paradigm applies to all programs which are created by one
  107. programmer and used by another member of the programming team.  Note that, by
  108. proxy, or whatever, the author of the library routines has in effect become
  109. a member of your programming team.
  110.  
  111.   You might care to write a program or two which use this header file,
  112. and for those who are motivated it might be an idea to re-implement localtime
  113. so that it understands Summer Time in the Southern Hemisphere. (!)
  114.  
  115. Using another totally trivial example in order to get the idea across please
  116. examine the hello world program printed immediately below.
  117.  
  118. /* ------------------------------------------------------------ */
  119.  
  120. #ident "@(#) hw_uc.h UPPER CASE version."
  121.  
  122. #define HELLO_MESSAGE "HELLO WORLD...\n";
  123.  
  124. /* ------------------------------------------------------------ */
  125.  
  126. #ident "@(#) Hello World"
  127.  
  128. #include <stdio.h>
  129. #include HW_H
  130.  
  131. #if !defined( HELLO_MESSAGE )
  132. # error "You have forgotten to define the header file name."
  133. #endif
  134.  
  135. char *format = "%s",
  136.      *hello = HELLO_MESSAGE;
  137.  
  138. main()
  139. {
  140.   printf ( format, hello );
  141.   }
  142.  
  143. /* ------------------------------------------------------------ */
  144.  
  145. You will no doubt notice that the symbol HW_H is used instead of a header file
  146. name. This gives us the ability to force the inclusion of any file we wish by
  147. defining the symbol HW_H to be the desired file name. It can be done like this:
  148.  
  149. cc -DHW_H="\"hw_uc.h\"" hello.c
  150.  
  151. The compiler output is placed, by default, in the file a.out, so to execute it
  152. issue the command:
  153.  
  154. a.out
  155.  
  156. Which, fairly obviously, produces the output:
  157.  
  158. HELLO WORLD...
  159.  
  160. As we are going to generate another version of the program we had better move
  161. the executable image file to another file name:
  162.  
  163. mv a.out hello_uc
  164.  
  165. Now to produce the other version issue the command line:
  166.  
  167. cc -DHW_H="\"hw_lc.h\"" hello.c; mv a.out hello_lc; hello_lc
  168.  
  169. Which compiles the other version of the hello.c program, using this version of
  170. the include file:
  171.  
  172. /* ------------------------------------------------------------ */
  173. #ident "@(#) hw_lc.h Lower Case version."
  174.  
  175. #define HELLO_MESSAGE "Hello World...\n";
  176. /* ------------------------------------------------------------ */
  177.  
  178. and then moves the executable image to a different file and executes it.
  179. Note that more than one command per line can be issued to the shell by
  180. separating the commands with the ';' delimiting character.
  181. Here - Surprise, Surprise - is the output of the second version.
  182.  
  183. Hello World...
  184.  
  185. I'd like to suggest that you use your editor to cut these example programs
  186. and the shell file below out of the mail file and have a play with them.
  187.  
  188. /* ----------------------------------------- */
  189.  
  190. # @(#) Shell file to do the compilations.
  191.  
  192. cc -o hello_uc -DHW_H="\"hw_uc.h\"" hello.c
  193. cc -o hello_lc -DHW_H="\"hw_lc.h\"" hello.c
  194.  
  195. /* ----------------------------------------- */
  196.  
  197.  
  198. #define
  199.  
  200.   This statement allows you to set up macro definitions. The word immediately
  201. after the #define, together with its arguments, is expanded in the program
  202. text to the whole of the rest of the line.
  203.  
  204. #define min(a, b) ((a<b) ? a : b )
  205.  
  206.   Some things to note:
  207.  
  208.   1) There isn't a space between the last character of the symbol being defined
  209.      and the opening parenthesis enclosing the arguments, and there MUST NOT BE
  210.      one.
  211.  
  212.   2) The code into which the macro is expanded MUST always be enclosed in
  213.      parentheses and for safety always use parentheses to get the arithmetic
  214.      right.
  215.  
  216.   3) Never EVER define a macro, and use it with a side effect. e.g.
  217.  
  218.   c = min ( a++, b);                              /* DON'T _EVER_ DO THIS!!! */
  219.  
  220.      Do you think that the value of 'a' will get advanced after the
  221.      macro is used? Well it WON'T. It gets incremented after the less
  222.      than test and before the values get assigned! I have written a tiny
  223.      program which uses the min macro above. Have a look at the output
  224.      from the pre-processor. Lesson One told you how to do this.
  225.      Now execute it and get an educative surprise!
  226.  
  227. /* ----------------------------------------- */
  228.  
  229. #include <stdio.h>
  230. #define min(a, b) ((a<b) ? a : b )
  231.  
  232. main()
  233. { int a,b,c;
  234.  
  235.   a = 1;
  236.   b = 2;
  237.   c = min ( a++, b);                              /* DON'T _EVER_ DO THIS!!! */
  238.   printf ( "a: %d, b: %d, c: %d\n", a, b, c );
  239.   }
  240.  
  241. /* ----------------------------------------- */
  242.  
  243.   4) You can continue a macro on the next line by putting a \ ( back-slash )
  244.      as THE VERY LAST character on the line. NOTHING, not even a space may
  245.      follow, as your compiler just can't handle it. I spent far too long trying
  246.      to find one of those really difficult bugs, and it turned out that this
  247.      was the problem - spaces are transparent aren't they?
  248.  
  249.   5) Using macros is fast and convenient, but they do take up a lot of memory
  250.      because the code is expanded and inserted into the output stream for
  251.      every occurrence of the macro in your code. There is a trade-off between
  252.      using a macro and a function.
  253.  
  254.   The symbol does not have to be the handle for a macro expansion, but can just
  255. be equated to a single constant. This is done many times over in the header
  256. files provided by the operating system vendor. Have a look in
  257. /usr/include/sys/file.h for an example of this.
  258.  
  259. #undef
  260.  
  261.   Not surprisingly this preprocessor command removes a symbol WHICH IS BEING
  262.   USED BY THE PRE-PROCESSOR - don't confuse it with compiler proper symbols.
  263.  
  264.   Note that the symbol can be a macro name, in which case the space
  265.   used for the code expansion is made available for re-use.
  266.  
  267. #if ( FLAG )
  268.  
  269.       /* Code in here is sent on to the compiler if FLAG is true. */
  270.  
  271. #else
  272.  
  273.       /* Code in here is sent on to the compiler if FLAG is false. */
  274.  
  275. #endif
  276.  
  277.   When the pre-processor encounters one of these, the lines of code between the
  278. #if and the corresponding #else or #endif are either skipped over or allowed to
  279. proceed to the compilation phase depending on the truth or falsity of the
  280. logical expression ( FLAG ). All the logical and boolean expressions available
  281. as part of the 'C' language are available here. You are also allowed to say:
  282.  
  283. #if defined( FLAG )  or,
  284. #if !defined( FLAG )
  285.  
  286.  
  287.   The symbol FLAG may be an expression which reduces to a boolean value.
  288.  
  289.   A convention which is adhered to quite well is that all pre-processor
  290. symbols are in UPPER_CASE so as to make them obvious.
  291.  
  292. #ifdef FLAG  or,
  293. #ifndef FLAG
  294.  
  295.   These two statements are the old fashioned way of testing whether a symbol is
  296. defined or not. They are absolutely the same as the previous example.
  297.  
  298.   There are two more pre-processor statements, namely the #pragma and
  299. the "stringizing" operator. The #pragma is used to alter the way in which
  300. the compiler works on a block of code, but it is completely implementation
  301. dependant and you must refer to your compiler manual. I can't help as
  302. they are all different. The "stringizing" operator is quite an advanced
  303. technique and will be dealt with later on.
  304.  
  305. Copyright notice:-
  306.  
  307. (c) 1993 Christopher Sawtell.
  308.  
  309. I assert the right to be known as the author, and owner of the
  310. intellectual property rights of all the files in this material,
  311. except for the quoted examples which have their individual
  312. copyright notices. Permission is granted for onward copying,
  313. but not modification, of this course and its use for personal
  314. study only, provided all the copyright notices are left in the
  315. text and are printed in full on any subsequent paper reproduction.
  316.  
  317. --
  318.  +----------------------------------------------------------------------+
  319.  | NAME   Christopher Sawtell                                           |
  320.  | SMAIL  215 Ollivier's Road, Linwood, Christchurch, 8001. New Zealand.|
  321.  | EMAIL  chris@gerty.equinox.gen.nz                                    |
  322.  | PHONE  +64-3-389-3200   ( gmt +13 - your discretion is requested )   |
  323.  +----------------------------------------------------------------------+
  324.  
  325. --
  326.  +----------------------------------------------------------------------+
  327.  | NAME   Christopher Sawtell                                           |
  328.  | SMAIL  215 Ollivier's Road, Linwood, Christchurch, 8001. New Zealand.|
  329.  | EMAIL  chris@gerty.equinox.gen.nz                                    |
  330.  | PHONE  +64-3-389-3200   ( gmt +13 - your discretion is requested )   |
  331.  +----------------------------------------------------------------------+
  332.